package com.tancire.net.service.impl;

import cn.hutool.core.util.IdUtil;
import com.tancire.common.core.redis.RedisCache;
import com.tancire.common.enums.ExpenseType;
import com.tancire.common.enums.PurseStatus;
import com.tancire.common.exception.net.NetActivityException;
import com.tancire.common.utils.DateUtils;
import com.tancire.net.domain.NetUser;
import com.tancire.net.domain.PurseInfo;
import com.tancire.net.mapper.PurseInfoMapper;
import com.tancire.net.service.IPurseInfoService;
import com.tancire.net.service.IPurseLogService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.tancire.common.constant.Constants.ACTIVITY_PREFIX;
import static com.tancire.common.constant.Constants.SUB_ACTIVITY_PREFIX;

/**
 * 会员钱包Service业务层处理
 *
 * @author chenchao
 * @date 2023-11-19
 */
@Service
public class PurseInfoServiceImpl implements IPurseInfoService {

    @Resource
    private PurseInfoMapper purseInfoMapper;

    @Resource
    private IPurseLogService purseLogService;

    @Resource
    private RedisCache redisCache;

    /**
     * 查询会员钱包
     *
     * @param id 会员钱包主键
     * @return 会员钱包
     */
    @Override
    public PurseInfo selectPurseInfoById(Long id) {
        return purseInfoMapper.selectPurseInfoById(id);
    }

    /**
     * 查询会员钱包列表
     *
     * @param purseInfo 会员钱包
     * @return 会员钱包
     */
    @Override
    public List<PurseInfo> selectPurseInfoList(PurseInfo purseInfo) {
        return purseInfoMapper.selectPurseInfoList(purseInfo);
    }

    /**
     * 新增会员钱包
     *
     * @param purseInfo 会员钱包
     * @return 结果
     */
    @Override
    public int insertPurseInfo(PurseInfo purseInfo) {
        purseInfo.setCreateTime(DateUtils.getNowDate());
        return purseInfoMapper.insertPurseInfo(purseInfo);
    }

    /**
     * 修改会员钱包
     *
     * @param purseInfo 会员钱包
     * @return 结果
     */
    @Override
    public int updatePurseInfo(PurseInfo purseInfo) {
        purseInfo.setUpdateTime(DateUtils.getNowDate());
        return purseInfoMapper.updatePurseInfo(purseInfo);
    }

    /**
     * 批量删除会员钱包
     *
     * @param ids 需要删除的会员钱包主键
     * @return 结果
     */
    @Override
    public int deletePurseInfoByIds(Long[] ids) {
        return purseInfoMapper.deletePurseInfoByIds(ids);
    }

    /**
     * 删除会员钱包信息
     *
     * @param id 会员钱包主键
     * @return 结果
     */
    @Override
    public int deletePurseInfoById(Long id) {
        return purseInfoMapper.deletePurseInfoById(id);
    }

    /**
     * 根据会员ID 查询钱包信息
     *
     * @param id
     * @return
     */
    @Override
    public PurseInfo selectPurseInfoByUserId(Long id) {
        return purseInfoMapper.selectPurseInfoByUserId(id);
    }

    @Override
    public void initPurseInfo(Long id, String userName) {
        if (null == id) {
            throw new NetActivityException("初始化钱包会员ID不能为空");
        }
        // 初始化信息
        PurseInfo purseInfo = new PurseInfo();
        purseInfo.setId(IdUtil.getSnowflakeNextId());
        purseInfo.setUserId(id);
        purseInfo.setUserName(userName);
        purseInfo.setActivePoints(BigDecimal.ZERO);
        purseInfo.setCashAmount(BigDecimal.ZERO);
        purseInfo.setPurseStatus(PurseStatus.NORMAL.getCode());
        this.purseInfoMapper.insertPurseInfo(purseInfo);
    }

    /**
     * 增加积分
     *
     * @param userId
     * @param addPoints
     * @param remark
     */
    @Transactional
    @Override
    public void addPoints(Long userId, BigDecimal addPoints, String remark) {
        PurseInfo purseInfo = this.purseInfoMapper.selectPurseInfoByUserId(userId);
        if (null == purseInfo) {
            throw new NetActivityException("会员信息校验失败，请联系管理员");
        }
        Object cacheObject = redisCache.getCacheObject(ACTIVITY_PREFIX + purseInfo.getId());
        if (null != cacheObject) {
            throw new NetActivityException("接口调用过于频繁，请稍后再试");
        }
        redisCache.setCacheObject(ACTIVITY_PREFIX + purseInfo.getId(), new Date().getTime(), 5, TimeUnit.SECONDS);
        // 增加积分 校验，不能大于最大单次增加积分量
        String topPointStr = redisCache.getCacheObject("sys_config:sys.adv.addPointsTop");
        BigDecimal topPoint = new BigDecimal(topPointStr);
        if (null == addPoints || addPoints.compareTo(topPoint) > 0) {
            throw new NetActivityException("风险控制，校验到异常刷积分");
        }
        // 调用接口增加积分
        BigDecimal activePoints = purseInfo.getActivePoints();
        if (null == activePoints) {
            activePoints = BigDecimal.ZERO;
        }
        activePoints = activePoints.add(addPoints);
        this.purseInfoMapper.updatePoints(purseInfo.getId(), activePoints);
        // 记录日志
        this.purseLogService.saveLog(purseInfo.getId(), addPoints, remark, ExpenseType.IN.getCode());
    }

    /**
     * 扣除积分
     *
     * @param userId
     * @param subPoints
     * @param remark
     */
    @Override
    public void subPoints(Long userId, BigDecimal subPoints, String remark) {
        PurseInfo purseInfo = this.purseInfoMapper.selectPurseInfoByUserId(userId);
        if (null == purseInfo) {
            throw new NetActivityException("您当前没有积分，请先获取积分");
        }
        Object cacheObject = redisCache.getCacheObject(SUB_ACTIVITY_PREFIX + userId);
        if (null != cacheObject) {
            throw new NetActivityException("接口调用过于频繁，请稍后再试");
        }
        redisCache.setCacheObject(SUB_ACTIVITY_PREFIX + userId, new Date().getTime(), 5, TimeUnit.SECONDS);
        // 校验积分余额是否够用
        BigDecimal activePoints = purseInfo.getActivePoints();
        if (null == activePoints || activePoints.compareTo(subPoints) < 0) {
            throw new NetActivityException("积分余额不足，请先获取积分");
        }
        // 调用接口减少积分
        activePoints = activePoints.subtract(subPoints);
        this.purseInfoMapper.updatePoints(purseInfo.getId(), activePoints);
        // 记录日志
        this.purseLogService.saveLog(purseInfo.getId(), subPoints, remark, ExpenseType.OUT.getCode());
        // 移除校验
        redisCache.deleteObject(SUB_ACTIVITY_PREFIX + userId);
    }

    /**
     * 同步更新钱包信息
     *
     * @param netUser
     */
    @Override
    public void asyncUpdatePurse(NetUser netUser) {
        this.purseInfoMapper.asyncUpdatePurse(netUser.getId(), netUser.getNickname());
    }
}
